Skip to content

Cairo: Add ERC20FlashMint extension#801

Open
immrsd wants to merge 9 commits into
OpenZeppelin:masterfrom
immrsd:cairo/erc20-flash-mint
Open

Cairo: Add ERC20FlashMint extension#801
immrsd wants to merge 9 commits into
OpenZeppelin:masterfrom
immrsd:cairo/erc20-flash-mint

Conversation

@immrsd
Copy link
Copy Markdown
Contributor

@immrsd immrsd commented May 6, 2026

Supports the ERC20FlashMintComponent for the ERC20 token in Cairo-alpha.

Configurable settings:

  • Max Flash LoanMax (default) or a non-negative custom cap;
  • Flash FeePercent of the loan amount (fractional values supported) or Custom (TODO stub);
  • Flash Fee DestinationBurn (default) or Fee receiver (passed as constructor arg, stored in storage);

@immrsd immrsd self-assigned this May 6, 2026
@immrsd immrsd requested review from a team as code owners May 6, 2026 14:26
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 029d410e-7013-49a9-a625-a3845f54ed77

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds ERC20 Flash Mint extension support to Cairo Alpha contracts, including configuration types, core builder logic with storage management, code generation wiring, UI controls, AI function definitions, and comprehensive test coverage.

Changes

ERC20 Flash Mint Feature

Layer / File(s) Summary
Data Shape & Types
packages/core/cairo_alpha/src/erc20.ts, packages/core/cairo_alpha/src/contract.ts, packages/common/src/ai/descriptions/cairo.ts
New ERC20Options fields for flash mint settings: flashmint, flashMintMaxAmount, flashMintFeeMode, flashMintFeePercent, flashMintFeeDestination. New exported types FlashMintFeeMode ('percent' | 'custom') and FlashMintFeeDestination ('burn' | 'fee_receiver'). New StorageMember interface with name and type fields.
Core Implementation
packages/core/cairo_alpha/src/erc20.ts, packages/core/cairo_alpha/src/contract.ts
Helpers parseFlashMintMaxAmount, parseFlashMintFeePercent, and buildFlashFeeOverrideBody parse and validate flash mint configuration. New addFlashMint function implements flash mint logic, overrides, and trait wiring. ContractBuilder gains storageMembers getter and addStorageMember(member) method with duplicate checks. New ERC20FlashMintComponent entry in component graph with storage, event, and impl wiring.
Code Generation
packages/core/cairo_alpha/src/generate/erc20.ts, packages/core/cairo_alpha/src/erc20.ts
Blueprint fields added for flash mint options in ERC20 generator. buildERC20 conditionally invokes addFlashMint when enabled.
Storage Rendering
packages/core/cairo_alpha/src/print.ts
printStorage updated to derive memberLines from contract.storageMembers and conditionally render Storage struct with or without members.
UI Integration
packages/ui/src/cairo_alpha/ERC20Controls.svelte
New Flash Mint section with Max/Custom radio controls for loan cap, Percent/Custom fee mode options, and conditional fee destination block. Imports resizeToFit utility. Adds reactive hasPositiveFlashFee flag and lastCustomMax state for toggling between modes. All inputs wired to opts fields with conditional enable/disable based on flashmint flag.
AI Function Definition
packages/ui/api/ai-assistant/function-definitions/cairo-alpha.ts
ERC20 AI function parameters expanded with five new flash mint fields: flashmint (boolean), flashMintMaxAmount (string), flashMintFeeMode (enum), flashMintFeePercent (string), flashMintFeeDestination (enum), each with descriptions.
Tests & Documentation
packages/core/cairo_alpha/src/tests/with_components_off/erc20/*, packages/core/cairo_alpha/src/tests/with_components_on/erc20/*, packages/core/cairo_alpha/CHANGELOG.md, .changeset/erc20-flash-mint.md
Comprehensive test suite covering flash mint enable/disable, custom max amounts, percent and custom fee modes, fee destinations, fractional fees, zero amount edge case, and validation errors (empty/non-numeric amounts, invalid percentages, out-of-range fees). Test snapshots document contract scaffolding and configuration. Changelog and changeset entries record the feature addition.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • bidzyyys
  • ericnordelo
  • ericglau
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Cairo: Add ERC20FlashMint extension' accurately and clearly describes the main change—adding support for the ERC20FlashMint extension in Cairo-alpha.
Description check ✅ Passed The description is directly related to the changeset, providing a clear summary of the ERC20FlashMint feature being added with its configurable settings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/core/cairo_alpha/src/tests/with_components_off/erc20/erc20.test.ts (1)

125-173: ⚡ Quick win

Add regression cases for numeric-but-unrepresentable inputs.

These negative tests cover malformed strings, but they still miss the cases most likely to regress here: a flashMintMaxAmount above u256::MAX, and a percent with so many fractional digits that the generated denominator no longer fits the emitted Cairo literal. Adding those would lock down the parser changes on the failure paths that currently escape local validation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/cairo_alpha/src/tests/with_components_off/erc20/erc20.test.ts`
around lines 125 - 173, Add two regression tests in the same suite that call
buildERC20 to assert validation failures for numeric-but-unrepresentable inputs:
one that sets flashMintMaxAmount to a numeric string greater than u256::MAX
(expecting the same OptionsError.messages.flashMintMaxAmount = 'Must be "max" or
a non-negative number'), and another that sets flashMintFeeMode: 'percent' with
flashMintFeePercent as a highly precise fractional string (many fractional
digits) that would overflow the denominator used to emit a Cairo literal
(expecting OptionsError.messages.flashMintFeePercent = 'Must be a number between
0 and 100'); mirror the existing test structure and assertions around buildERC20
to ensure these failure paths are covered.
packages/ui/src/cairo_alpha/ERC20Controls.svelte (1)

38-42: 💤 Low value

Consider guarding against undefined flashMintMaxAmount during initialization.

If opts.flashMintMaxAmount is undefined at component mount (before defaults are fully applied), the ternary only checks for 'max', potentially assigning undefined to lastCustomMax despite the string type annotation.

🛡️ Suggested defensive initialization
-  let lastCustomMax: string = opts.flashMintMaxAmount === 'max' ? '0' : opts.flashMintMaxAmount;
+  let lastCustomMax: string = (!opts.flashMintMaxAmount || opts.flashMintMaxAmount === 'max') ? '0' : opts.flashMintMaxAmount;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/cairo_alpha/ERC20Controls.svelte` around lines 38 - 42, The
initialization can assign undefined to lastCustomMax if opts.flashMintMaxAmount
is undefined; change the initialization and the reactive update to defensively
default undefined to a safe string (e.g., '0') and coerce any non-'max' value to
String so lastCustomMax is always a string; update references to the symbols
lastCustomMax and opts.flashMintMaxAmount (both in the initial let and the $:
reactive block) to perform an explicit undefined check and String(...)
conversion instead of only comparing to 'max'.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/cairo_alpha/src/erc20.ts`:
- Around line 397-409: The override created when overridesMax is true for
flashMintConfigTrait::max_flash_loan ignores total_supply and can return a cap
larger than the remaining mint headroom; modify the function body (the fn
created for name 'max_flash_loan') to compute the remaining headroom as
u256::MAX - total_supply and return the minimum of customMax and that remaining
headroom (while still returning 0 if token != get_contract_address()); ensure
u256 arithmetic/underflow is handled correctly so you clamp to remaining =
u256::MAX - total_supply and return min(customMax, remaining).
- Around line 329-349: The parseFlashMintFeePercent function can produce an
arbitrarily large decimalScale/denominator (from decimalDigits) which may
overflow the u256 used later; add a guard after computing
decimalDigits/decimalScale that ensures decimalScale and the resulting
denominator (100n * decimalScale) fit within the u256 limit and reject inputs
with too many fractional digits by throwing OptionsError; specifically check
decimalScale <= MAX_DECIMAL_SCALE (or denominator <= MAX_U256 where MAX_U256 =
2n ** 256n - 1n) and reference the symbols decimalDigits, decimalScale,
denominator, and OptionsError in the check.
- Around line 319-326: The parseFlashMintMaxAmount path currently returns any
BigInt size and can emit out-of-range Cairo literals; modify
parseFlashMintMaxAmount to mirror premint's validation by converting the
computed BigInt (from getInitialSupply(value, Number(decimals))) through
toUint(..., 'u256') and return that value, and if toUint throws/returns an
error, surface it as an OptionsError for flashMintMaxAmount; keep the existing
checks for value === 'max' (return null) and the premintPattern/empty-string
validation that throws OptionsError.

---

Nitpick comments:
In `@packages/core/cairo_alpha/src/tests/with_components_off/erc20/erc20.test.ts`:
- Around line 125-173: Add two regression tests in the same suite that call
buildERC20 to assert validation failures for numeric-but-unrepresentable inputs:
one that sets flashMintMaxAmount to a numeric string greater than u256::MAX
(expecting the same OptionsError.messages.flashMintMaxAmount = 'Must be "max" or
a non-negative number'), and another that sets flashMintFeeMode: 'percent' with
flashMintFeePercent as a highly precise fractional string (many fractional
digits) that would overflow the denominator used to emit a Cairo literal
(expecting OptionsError.messages.flashMintFeePercent = 'Must be a number between
0 and 100'); mirror the existing test structure and assertions around buildERC20
to ensure these failure paths are covered.

In `@packages/ui/src/cairo_alpha/ERC20Controls.svelte`:
- Around line 38-42: The initialization can assign undefined to lastCustomMax if
opts.flashMintMaxAmount is undefined; change the initialization and the reactive
update to defensively default undefined to a safe string (e.g., '0') and coerce
any non-'max' value to String so lastCustomMax is always a string; update
references to the symbols lastCustomMax and opts.flashMintMaxAmount (both in the
initial let and the $: reactive block) to perform an explicit undefined check
and String(...) conversion instead of only comparing to 'max'.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7e84975b-b3e6-4358-99ce-0250a7f0e4ca

📥 Commits

Reviewing files that changed from the base of the PR and between 603a84c and 0f2157c.

⛔ Files ignored due to path filters (2)
  • packages/core/cairo_alpha/src/tests/with_components_off/erc20/erc20.test.ts.snap is excluded by !**/*.snap
  • packages/core/cairo_alpha/src/tests/with_components_on/erc20/erc20.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (13)
  • .changeset/erc20-flash-mint.md
  • packages/common/src/ai/descriptions/cairo.ts
  • packages/core/cairo_alpha/CHANGELOG.md
  • packages/core/cairo_alpha/src/contract.ts
  • packages/core/cairo_alpha/src/erc20.ts
  • packages/core/cairo_alpha/src/generate/erc20.ts
  • packages/core/cairo_alpha/src/print.ts
  • packages/core/cairo_alpha/src/tests/with_components_off/erc20/erc20.test.ts
  • packages/core/cairo_alpha/src/tests/with_components_off/erc20/erc20.test.ts.md
  • packages/core/cairo_alpha/src/tests/with_components_on/erc20/erc20.test.ts
  • packages/core/cairo_alpha/src/tests/with_components_on/erc20/erc20.test.ts.md
  • packages/ui/api/ai-assistant/function-definitions/cairo-alpha.ts
  • packages/ui/src/cairo_alpha/ERC20Controls.svelte

Comment thread packages/core/cairo_alpha/src/erc20.ts Outdated
Comment thread packages/core/cairo_alpha/src/erc20.ts Outdated
Comment thread packages/core/cairo_alpha/src/erc20.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Wizard]: Add ERC-20 FlashMint Extension

1 participant